﻿package com.ecr.hub.model.hub;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.ecr.hub.ApplicationException;
import com.ecr.hub.FunctionnalApplicationException;
import com.ecr.hub.RailDestinationException;
import com.ecr.hub.RailNotAvailableException;
import com.ecr.hub.RailNotAvailableNorthException;
import com.ecr.hub.RailNotAvailableSouthException;
import com.ecr.hub.RailUtilLengthException;
import com.ecr.hub.WagonPosTheoriqueException;
import com.ecr.hub.front.bean.managed.RepositoryManagedBean;
import com.ecr.hub.model.enumeration.HubBundleType;
import com.ecr.hub.model.enumeration.HubErrorLevel;
import com.ecr.hub.model.enumeration.HubStack;
import com.ecr.hub.model.rail.Rail;
import com.ecr.hub.model.wagon.Wagon;
import com.ecr.hub.util.LabelUtils;
import com.ecr.hub.util.MessageUtils;

/**
 * L'idée principale de ce controller est d'une part de pouvoir gérer le
 * positionnement des wagons et l'affichage des voies, mais aussi d'éviter de
 * mettre de l'intelligence dans les différents beans (nottament celui de la
 * voie). Ainsi le bean rail correspond véritablement à la notion de bean et ne
 * contient que des propriétés , des getters et des setters. Le code est moins
 * abstrait (il aurait été plus propre par exemple de gérer le calcul de la
 * longueur des voies dans une méthode addWagon ou delWagon du bean rail) mais
 * cela permet d'être plus propre au niveau du bean et déviter de faire des
 * objets intermédiaires (wrapper sur le bean rail etc..).
 */
public class HubTrafficController {

	// La liste totale des voies pour affichage sur le hub.
	private List<Rail> lstRails;
	// Tableau interne pour aider à retrouver rapidement une voie.
	private Map<Integer, Integer> mapRails;
	// La liste pour les voies de reception.
	private List<Rail> lstRightRails;
	// La liste pour les voies de tri.
	private List<Rail> lstCenterRails;
	// La liste pour voies de formation et autres.
	private List<Rail> lstLeftRails;

	/**
	 * Constructeur, on initialise les trois panneaux qui seront représentés à
	 * l'écran et on demande la répartition des voies.
	 */
	public HubTrafficController(List<Rail> lstRails) {

		lstRightRails = new ArrayList<Rail>();
		lstCenterRails = new ArrayList<Rail>();
		lstLeftRails = new ArrayList<Rail>();
		dispatchLstRails(lstRails);
	}

	/**
	 * Placement des différentes voies sur le hub. Cette méthode est appelée une
	 * seule fois dans la cadre de la session utilisateur, au momment ou
	 * l'utilisateur accède pour la première fois au bean de visualisation du
	 * hub. par la suite, c'est la méthode "setTraffic" qui est rappelée à
	 * chaque raffraîchissement de la vue. La création d'une map avec deux
	 * entiers permet de se retrouver rapidement lors des futures recherches
	 * d'une voie avaec son identifiant interne dans la liste des voies
	 * lstRails.
	 */
	private void dispatchLstRails(List<Rail> lstRails) {
		this.lstRails = lstRails;
		mapRails = new Hashtable<Integer, Integer>();
		for (int i = 0; i < lstRails.size(); i++) {
			mapRails.put(Integer.valueOf(lstRails.get(i).getId()),
					Integer.valueOf(i));
			if (lstRails.get(i).getTypeBundle().getId() == HubBundleType.ARRIVAL
					.getValue()) {
				lstLeftRails.add(lstRails.get(i));
			} else if (lstRails.get(i).getTypeBundle().getId() == HubBundleType.FORMATION
					.getValue()
					|| lstRails.get(i).getTypeBundle().getId() == HubBundleType.DEPARTURE
							.getValue()) {
				lstRightRails.add(lstRails.get(i));
			} else {
				lstCenterRails.add(lstRails.get(i));
			}
		}
	}

	/**
	 * Ceci est une des méthodes les plus importantes de l'application. Elle est
	 * chargée de la répartition des wagons sur le hub, entre les différentes
	 * voies. Chaque wagon contient sa position à l'interieur d'une voie donnée.
	 * Tout le système est basé sur le fait que la liste des wagons est
	 * récupérée triée par voies et par positions. On effectue toutefois des
	 * contrôles pour vérifier que la liste arrive bien dans le bon ordre. Afin
	 * d'éviter les calculs du type +1, la position stockée dans le wagon est
	 * exactement celle de la LinkedList, le premier wagon commence donc = 0 et
	 * non 1. Cela permet de plus de vérifier rapidement si la taille de la
	 * liste correspond au wagon que l'on veut ajouter (taille de la liste =
	 * position du wagon à ajouter). Un fois tous les wagons ajoutés, on,
	 * demande le calcul des longueurs pour toutes les voies.
	 */
	public void setTraffic(List<Wagon> lstwagons) throws ApplicationException {

		clearTraffic();

		for (Wagon wagon : lstwagons) {
			Rail rail = getRailById(wagon.getCurrentPos().getPosRailId());
			if (rail == null) {
				throw new ApplicationException(
						"Hub : Impossible de récupérer la voie dans la liste.",
						HubErrorLevel.FATAL);
			} else if (rail.getId() != wagon.getCurrentPos().getPosRailId()) {
				throw new ApplicationException(
						"Hub : La voie récupérée ne correspond pas à celle du wagon.",
						HubErrorLevel.FATAL);
			} else if (rail.getLstWagons().size() != wagon.getCurrentPos()
					.getPosNum()) {
				throw new ApplicationException(
						"Hub : La position du wagon ne correspond pas à celle disponible dans la voie.",
						HubErrorLevel.FATAL);
			}
			rail.getLstWagons().add(wagon);
		}

		checkAllRailsLength();
	}

	/**
	 * Cette méthode est primordiale, elle permet de retrouver une voie par
	 * rapport à son identifiant interne dans la liste des voies (lstRails).
	 * Ainsi par exemple, la voie de triage n° 43 à comme identifiant interne le
	 * numéro 48. En passant 48 en parametre, on retrouve l'objet voie dans la
	 * liste des voies sans faire d'itérations inutiles.
	 */
	public Rail getRailById(int railId) throws ApplicationException {

		Rail rail = lstRails.get(mapRails.get(Integer.valueOf(railId)));
		if (null == rail)
			throw new ApplicationException(
					"Hub : Impossible de récupérer la voie à partir de l'identifiant : "
							+ railId, HubErrorLevel.FATAL);
		return rail;
	}

	/**
	 * On demande la calcul des longueurs utiles pour l'ensemble des voies
	 * disponibles sur le hub. Cette méthode est juste créée pour éviter de
	 * lancer un calcul à chaque fois que l'on ajoute un wagon sur une voie dans
	 * des méthodes telles que "setTraffic" par exemple. Par contre, il n'y a
	 * pas besoin d'avoir les exceptions avec les messages de retour.
	 */
	private void checkAllRailsLength() {

		for (Rail rail : lstRails) {
			try {
				checkRailLength(rail);
			} catch (RailUtilLengthException e) {
				// RAS.
			}
		}
	}

	/**
	 * Méthode dédiée au calcul de la longueur utile sur la voie en fonction des
	 * différents wagons qui sont positionnés. On balaye l'ensemble de la voie
	 * et on décrémente avec la longueur de chaque wagon trouvé, qu'il soit en
	 * position réelle ou en position théorique (Il s'agit juste d'une alerte).
	 */
	private void checkRailLength(Rail rail) throws RailUtilLengthException {
		float length = RepositoryManagedBean.DEFAULT_WAGON_TOTAL_LENGTH;
		rail.setUtilLengthAlert(false);
		rail.setCalcUtilLength(rail.getUtilLength());
		for (Wagon wagon : rail.getLstWagons()) {
			if (wagon.getType().getTotalLength() == 0) {
				rail.setUtilLengthAlert(true);
			} else {
				length = wagon.getType().getTotalLength();
			}
			rail.setCalcUtilLength(rail.getCalcUtilLength() - length);
		}
		if (0 > rail.getCalcUtilLength())
			throw new RailUtilLengthException(
					MessageUtils.getStringMessageError("hub.error.length"));
	}

	/**
	 * Méthode dédiée à la vérification du positionnement d'un wagon sur la
	 * bonne voie, selon la destination du wagon, la voie sur laquelle on désire
	 * le positionner est elle la bonne ? Il faut que la voie soit une voie de
	 * tri et qu'une destination lui soit affectée, sinon on laisse passer (Il
	 * s'agit juste d'une alerte).
	 */
	private void checkRailDestination(Wagon wagon) throws ApplicationException,
			RailDestinationException {

		Rail rail = getRailById(wagon.getCurrentPos().getPosRailId());

		if (rail.getTypeBundle().getId() == HubBundleType.SORT.getValue()
				&& rail.getDestinationId() != 0
				&& wagon.getDestinationId() != rail.getDestinationId()) {
			throw new RailDestinationException(
					MessageUtils.getStringMessageError("hub.error.rail"));
		}
	}

	/**
	 * Méthode très simple pour juste vérifier si la voie est disponible ou non
	 * pour positionner un wagon.
	 * 
	 * @throws ApplicationException
	 */
	private void checkRailAvailable(Rail rail) throws ApplicationException {
		try {
			checkRailAvailable(rail.getId());
		} catch (RailNotAvailableException e) {
			throw new RailNotAvailableException(
					MessageUtils
							.getStringMessageError("hub.error.rail.available"));
		} catch (RailNotAvailableNorthException e) {
			throw new RailNotAvailableNorthException(
					MessageUtils
							.getStringMessageError("hub.error.rail.available.nord"));
		} catch (RailNotAvailableSouthException e) {
			throw new RailNotAvailableSouthException(
					MessageUtils
							.getStringMessageError("hub.error.rail.available.sud"));
		}
	}

	/**
	 * Cette méthode effectue le même contrôle que la méthode ci-dessus mais
	 * elle est accessible à l'exterieur et prend simplement l'identifiant de la
	 * voie en paramètre, et non la voie elle même. De plus on se contente de
	 * renvoyer un message banalisé, c'est la méthode appelante qui se charge de
	 * mettre le message désiré.
	 */
	public void checkRailAvailable(int railId)
			throws RailNotAvailableException, ApplicationException {

		Rail rail = getRailById(railId);
		if (rail.getAvailable() == 0)
			throw new RailNotAvailableException(
					MessageUtils
							.getStringMessageError("Hub : La voie n'est pas disponible."));
		if (rail.getAvailable() == 2)
			throw new RailNotAvailableNorthException(
					MessageUtils
							.getStringMessageError("Hub : La voie n'est pas disponible coté Nord."));
		if (rail.getAvailable() == 3)
			throw new RailNotAvailableSouthException(
					MessageUtils
							.getStringMessageError("Hub : La voie n'est pas disponible coté Sud."));
	}

	/**
	 * Cette méthode effectue le même contrôle que la méthode ci-dessus mais
	 * elle est accessible à l'exterieur et prend simplement l'identifiant de la
	 * voie en paramètre, et non la voie elle même. De plus on se contente de
	 * renvoyer un message banalisé, c'est la méthode appelante qui se charge de
	 * mettre le message désiré.
	 */
	public void checkRailAvailableNorth(int railId)
			throws RailNotAvailableException, ApplicationException {

		try {
			checkRailAvailable(railId);
		} catch (RailNotAvailableSouthException e) {
			// RAS South
		} catch (RailNotAvailableException e) {
			throw new RailNotAvailableException(
					MessageUtils
							.getStringMessageError("hub.error.rail.available"));
		} catch (RailNotAvailableNorthException e) {
			throw new RailNotAvailableNorthException(
					MessageUtils
							.getStringMessageError("hub.error.rail.available.nord"));
		}
	}
	
	/**
	 * Cette méthode effectue le même contrôle que la méthode ci-dessus mais
	 * elle est accessible à l'exterieur et prend simplement l'identifiant de la
	 * voie en paramètre, et non la voie elle même. De plus on se contente de
	 * renvoyer un message banalisé, c'est la méthode appelante qui se charge de
	 * mettre le message désiré.
	 */
	public void checkRailAvailableOnly(int railId)
			throws RailNotAvailableException, ApplicationException {

		try {
			checkRailAvailable(railId);
		} catch (RailNotAvailableSouthException e) {
			// RAS South
		} catch (RailNotAvailableException e) {
			throw new RailNotAvailableException(
					MessageUtils
							.getStringMessageError("hub.error.rail.available"));
		} catch (RailNotAvailableNorthException e) {
			//RAS
		}
	}

	/**
	 * Cette méthode est utilisée pour vérifier le dépilage des wagons. On
	 * vérifie qu'aucun wagon n'est en position théorique dans le nombre de
	 * wagons à dépiler sur la voie.
	 */
	public void checkWagonsPosReal(int railId, int nbWagonsToCheck)
			throws ApplicationException {
		Rail rail = getRailById(railId);
		for (Wagon wagon : rail.getLstWagons()) {
			if (!wagon.getCurrentPos().isPosReal()
					&& wagon.getCurrentPos().getPosNum() < nbWagonsToCheck - 1)
				throw new WagonPosTheoriqueException(
						"Hub : Un des wagons est encore en position théorique");
		}
	}

	/**
	 * Après un placement de wagon(s) ou une suppression de wagons(s) sur une
	 * voie, on redemande la calcul des indexs de positionnement de chaque wagon
	 * présent sur la voie. (Si un wagon en position 1 est supprimé de la voie,
	 * le suivant n'est plus en position 2 mais en position 1, etc...).
	 * 
	 * Bien que très simple, cette méthode est absolument primordiale pour le
	 * fonctionnement du Hub !!
	 */
	private void updatePosNumRail(Rail rail) {

		for (int i = 0; i < rail.getLstWagons().size(); i++) {
			rail.getLstWagons().get(i).getCurrentPos().setPosNum(i);
		}
	}

	/**
	 * Suppression d'un wagon sur une voie. Pour l'ancienne position du wagon il
	 * est inutile de la stocker car entre temps d'autres wagons ont pu êtres
	 * rajoutés et décaler la position du wagon (trop complexe). Il faut donc
	 * itérer sur la voie jusqu'à retrouver le wagon. A la fin, on demande le
	 * recalcul des positions pour l'ensemble des wagons de la voie.
	 */
	public void deleteWagon(Wagon wagon) throws ApplicationException {

		boolean wagonDeleted = false;
		Rail rail = getRailById(wagon.getCurrentPos().getPosRailId());

		for (Iterator<Wagon> it = rail.getLstWagons().iterator(); it.hasNext();) {
			if (it.next().getId() == wagon.getId()) {
				wagonDeleted = true;
				it.remove();
				break;
			}
		}
		if (!wagonDeleted)
			throw new ApplicationException(
					"Hub : Impossible d'enlever le wagon"
							+ "de la prédécente demande de positionnement",
					HubErrorLevel.FATAL);

		// Recalcul des indexs pour l'ensemble des wagons sur la voie.
		updatePosNumRail(rail);
	}

	/**
	 * Méthode pour mettre à jour le statut d'un wagon dans le hub. On récupère
	 * le rail du wagon, on retrouve la wagon et on modifie son statut.
	 */
	public void updateWagonStatus(Wagon wagon, boolean posReal)
			throws ApplicationException {

		Rail rail = getRailById(wagon.getCurrentPos().getPosRailId());
		if (rail.getLstWagons().size() < wagon.getCurrentPos().getPosNum())
			throw new ApplicationException(
					"Hub : Impossible de récupérer le wagon"
							+ "pour effectuer le changement de statut.",
					HubErrorLevel.FATAL);

		Wagon hubWagon = rail.getLstWagons().get(
				wagon.getCurrentPos().getPosNum());

		if (hubWagon.getId() != wagon.getId())
			throw new ApplicationException(
					"Hub : Impossible de récupérer le wagon"
							+ "pour effectuer le changement de statut.",
					HubErrorLevel.FATAL);

		// Contrôle de la position théorique d'un wagon en n-1.
		if (posReal && rail.getLstWagons().size() > 0
				&& wagon.getCurrentPos().getPosNum() > 0) {
			if (!(rail.getLstWagons()
					.get(wagon.getCurrentPos().getPosNum() - 1))
					.getCurrentPos().isPosReal())
				throw new WagonPosTheoriqueException(
						"Hub : un wagon est en position "
								+ "théorique sur la voie.");
		}
		hubWagon.getCurrentStatus().setId(wagon.getNextStatus().getId());
		hubWagon.getCurrentPos().setPosReal(posReal);
		// Juste pour être propre mais sera écrasé par le retrait en base.
		hubWagon.getCurrentStatus().setLabel("");
		hubWagon.getCurrentStatus().setComment("");
	}

	/**
	 * Mise à jour de la voie de provenance pour un wagon. cette méthode est
	 * surtout utilisée (voire exclusivement) dans le cas ou le train est arrivé
	 * après le programme de travail. on retouve donc les wagons dans le traffic
	 * et on met à jour la voie de provenance avec la voie de réception.
	 */
	public void updateWagonFromRail(Wagon wagon) throws ApplicationException {

		Rail rail = getRailById(wagon.getCurrentPos().getPosRailId());
		if (rail.getLstWagons().size() < wagon.getCurrentPos().getPosNum())
			throw new ApplicationException(
					"Hub : Impossible de récupérer le wagon"
							+ "pour effectuer le changement de provenance.",
					HubErrorLevel.FATAL);

		Wagon hubWagon = rail.getLstWagons().get(
				wagon.getCurrentPos().getPosNum());

		if (hubWagon.getId() != wagon.getId())
			throw new ApplicationException(
					"Hub : Impossible de récupérer le wagon"
							+ "pour effectuer le changement de provenace.",
					HubErrorLevel.FATAL);

		// Met à jour le wagon dans le traffic.
		hubWagon.setFromRail(wagon.getFromRail());
	}

	/**
	 * Mise à jour d'un wagon dans le traffic avec le commentaire saisi.
	 * Malheureusement on est obligé de procéder de cette manière car le wagon
	 * est déjà positionné dans le traffic au momment ou le coordinateur peut
	 * saisir le commentaire, il faut donc retrouver le wagon et placer le
	 * commentaire avant que le traffic soit "flushé" dans la base.
	 */
	public void updateWagonForComment(Wagon wagon) throws ApplicationException {
		if (wagon.getComment() != null
				&& wagon.getComment().trim().length() > 0) {
			Rail rail = getRailById(wagon.getNextPos().getPosRailId());
			for (Wagon w : rail.getLstWagons()) {
				if (w.getId() == wagon.getId()) {
					w.setComment(wagon.getComment());
					break;
				}
			}
		}
	}

	/**
	 * Cette méthode ne fait qu'appeler la méthode "moveWagon" mais bloque les
	 * exceptions de type Fonctionnelles (résultats des tests de positionnement)
	 * puisque le coordinateur peut choisir de passer toutes les alertes. cela
	 * évite d'avoir des try / catch dans les méthodes appelantes et rend le
	 * code plus lisible.
	 */
	public void moveWagonAExOnly(Wagon wagon, HubStack stack, boolean posReal)
			throws ApplicationException {
		try {
			moveWagon(wagon, stack, posReal);
		} catch (FunctionnalApplicationException e) {
			// RAS.
		}
	}

	/**
	 * Méthode interne qui centralise toute la gestion pour le déplacement d'un
	 * wagon d'un point A à un point B. Cette méthode 1) Vérifie si une première
	 * demande de positionnement a été faite et l'annule le cas échéant. 2)
	 * effectue les contrôles nécessaires. 3) Positionne le wagon en position
	 * théorique ou réelle (selon le besoin) à son futur emplacement. Le statut
	 * doit être géré dans une fonction à part car en entrée on a pas forcement
	 * un wagon qui vient directement d'une voie (donc on ne peut agir dessus).
	 */
	public void moveWagon(Wagon wagon, HubStack stack, boolean posReal)
			throws ApplicationException {

		// A tout hazard si on a récupéré un wagon null (theoriquement
		// impossible).
		if (null == wagon)
			throw new ApplicationException("Hub : Le wagon pour la demande "
					+ "de positionnement est nul.", HubErrorLevel.FATAL);

		// Réinitialisation des erreurs pour le wagon.
		wagon.reinitErrorIndicator();

		// Si le wagon à bouger est en position théorique on lève une alerte.
		if (wagon.getCurrentPos().getPosRailId() != 0
				&& !wagon.getCurrentPos().isPosReal())
			wagon.setErrorMessage("hub.error.theo");

		// On récupère la voie de la demande de positionnement.
		Rail rail = getRailById(wagon.getNextPos().getPosRailId());

		// Si la demande est en position réelle alors on vérifie qu'il n'y a pas
		// des wagons en position théorique sur la voie. (sauf si demande
		// première position).
		if (posReal && stack != HubStack.POS_BEGIN
				&& rail.getLstWagons().size() > 0) {
			// On récupère la position à vérifier.
			int posNumToCheck = (stack == HubStack.POS_AT && wagon.getNextPos()
					.getPosNum() < rail.getLstWagons().size()) ? wagon
					.getNextPos().getPosNum() - 1
					: rail.getLstWagons().size() - 1;

			// On effectue la vérification
			if (!rail.getLstWagons().get(posNumToCheck).getCurrentPos()
					.isPosReal())
				throw new WagonPosTheoriqueException(
						"Hub : Il y a des wagons en position "
								+ "théorique sur cette voie.");
		}

		// Une précédente demande a t'elle été effectuée sur le wagon, si oui on
		// annule la demande. (On positionne temporairement le rail dans la
		// position courante car la fonction de suppression n'efface un wagon
		// que sur sa position courante 99% de l'utilisation).
		if (wagon.getLastPos().getPosRailId() != 0) {
			wagon.getCurrentPos().setPosRailId(
					wagon.getLastPos().getPosRailId());
			deleteWagon(wagon);
			wagon.getCurrentPos().setPosRailId(0);
		}

		// Clonnage du wagon (comme on le déplace il passe en position théorique
		// mais il ne faut surtout pas conserver la référence sur le wagon qui
		// peut être en position réelle et qui lui, ne bouge pas).
		Wagon wagonClone = (Wagon) wagon.clone();

		// On prend l'ancienne position du wagon et on construit la chaine pour
		// connaitre sa voie de provenance.
		if (wagonClone.getCurrentPos().getPosRailId() > 0)
			wagonClone.setFromRail(getRailDesignation(wagonClone
					.getCurrentPos().getPosRailId()));

		// On positionne le clone du wagon.
		wagonClone.getCurrentPos().setPosReal(posReal);
		wagonClone.getCurrentPos().setPosRailId(
				wagonClone.getNextPos().getPosRailId());

		// On ajoute à la fin de la pile.
		if (stack == HubStack.POS_END) {
			wagonClone.getCurrentPos().setPosNum(rail.getLstWagons().size());
			rail.getLstWagons().add(wagonClone);

			// On ajoute au début de la pile ou à une position x, on recalcule
			// tous les indexs de positionnement.
		} else {
			if (stack == HubStack.POS_BEGIN) {
				rail.getLstWagons().add(0, wagonClone);
			} else if (stack == HubStack.POS_AT) {
				// On contrôle que la position demandé ne sorte pas des indexs,
				// si oui, alors on ajoute simplement à la fin (réentrance).
				if (wagon.getNextPos().getPosNum() > rail.getLstWagons().size()) {
					moveWagon(wagon, HubStack.POS_END, posReal);
				} else {
					rail.getLstWagons().add(
							wagonClone.getNextPos().getPosNum(), wagonClone);
				}
			}
			// On recalcule tous les indexs des wagons sur le rail.
			updatePosNumRail(rail);
		}
		// On positionne la voie dans la dernière demande du wagon pour pouvoir
		// effacer la dernière demande si le coordinateur bouge à nouveau le
		// wagon.
		wagon.getLastPos().setPosRailId(wagon.getNextPos().getPosRailId());

		// On effectue les contrôles juste pour les alertes utilisateur.
		// Attention respecter l'ordre car ce sont des exceptions
		// qui sont lancées.
		checkRailAvailable(rail);
		checkRailLength(rail);
		checkRailDestination(wagonClone);
	}

	/**
	 * Récupération d'une chaine de caractères de type "56 (AMBERIEU)" à partir
	 * de l'indentifiant interne d'une voie. On construit une chaine avec le
	 * numéro de la voie et la destination associée ou le type de la voie s'il
	 * ne s'agit pas d'une voie de tri.
	 */
	public String getRailDesignation(int railId) throws ApplicationException {

		StringBuffer strFromRail = new StringBuffer();
		if (railId > 0) {
			Rail fromRail = getRailById(railId);
			strFromRail.append(fromRail.getNumber()).append(" (");
			if (fromRail.getTypeBundle().getId() == HubBundleType.SORT
					.getValue()) {
				strFromRail.append(fromRail.getDestinationLabel());
			} else {
				strFromRail.append(fromRail.getTypeBundle().getLabel());
			}
			strFromRail.append(")");
			return strFromRail.toString();
		}
		return LabelUtils.getLabel("common.nc");
	}

	/**
	 * Vide le hub de toutes les données wagon. On ne garde que les données
	 * voie. On prend chaque voie, on récupère la liste des wagons et on demande
	 * la réinitialisation de la liste.
	 */
	public void clearTraffic() {
		for (Rail rail : lstRails) {
			rail.getLstWagons().clear();
		}
	}

	// ******************************
	// Les getters et les setters.
	// ******************************

	public List<Rail> getLstRightRails() {
		return lstRightRails;
	}

	public List<Rail> getLstCenterRails() {
		return lstCenterRails;
	}

	public List<Rail> getLstLeftRails() {
		return lstLeftRails;
	}

	public List<Rail> getLstRails() {
		return lstRails;
	}
}
